/*
 *  matrix_helpers.c
 *  Renderbunny
 *
 *  Created by Holmes Futrell on 1/26/11.
 *  Copyright 2011 __MyCompanyName__. All rights reserved.
 *
 */

#include "matrix_helpers.h"

mat4 rb_mat4_normal_matrix( const mat4 *mat ) {
	mat4 result = rb_mat4_inverse(mat);
	return rb_mat4_transpose(&result);
}	

mat4 rb_mat4_rotate(float theta, float x, float y, float z) {
	
	mat4 result = rb_mat4_zero();
	
	float mag = sqrtf( x*x + y*y + z*z );
	x /= mag;
	y /= mag;
	z /= mag;
	
	float c = cos(theta);
	float s = sin(theta);
	
	result.entries[M4E(0,0)] = x*x*(1.0f-c)+c;
	result.entries[M4E(0,1)] = x*y*(1.0f-c)-z*s;
	result.entries[M4E(0,2)] = x*z*(1.0f-c)+y*s;
	result.entries[M4E(1,0)] = y*x*(1.0f-c)+z*s;
	result.entries[M4E(1,1)] = y*y*(1.0f-c)+c;
	result.entries[M4E(1,2)] = y*z*(1.0f-c)-x*s;
	result.entries[M4E(2,0)] = x*z*(1.0f-c)-y*s;
	result.entries[M4E(2,1)] = y*z*(1.0f-c)+x*s;
	result.entries[M4E(2,2)] = z*z*(1.0f-c)+c;
	result.entries[M4E(3,3)] = 1.0f; 
	
	return result;
}

mat4 rb_mat4_ortho(float left, float right, float bottom,float top,float zNear,float zFar) {
	mat4 result = rb_mat4_zero();
	
	result.entries[ M4E( 0, 0 ) ] = 2.0f / ( right - left );
	result.entries[ M4E( 1, 1 ) ] = 2.0f / ( top - bottom );
	result.entries[ M4E( 2, 2 ) ] = -2.0f / ( zFar - zNear );
	
	float tx = - (right + left) / (right - left);
	float ty = - (top + bottom) / (top - bottom);
	float tz = - (zFar + zNear) / (zFar - zNear);
	
	result.entries[ M4E( 0, 3 ) ] = tx;
	result.entries[ M4E( 1, 3 ) ] = ty;
	result.entries[ M4E( 2, 3 ) ] = tz;
	result.entries[ M4E( 3, 3 ) ] = 1;
	
	return result;
	
}

mat4 rb_mat4_look_at(float eyeX,
					 float eyeY,
					 float eyeZ,
					 float centerX,
					 float centerY,
					 float centerZ,
					 float upX,
					 float upY,
					 float upZ) {
	
	vec3 f = normalize_vec3(difference_vec3( make_vec3( centerX, centerY, centerZ ),
											make_vec3( eyeX, eyeY, eyeZ ))
							);
	vec3 UP_prime = normalize_vec3(make_vec3(upX, upY, upZ));
	
	vec3 s = cross_vec3(f, UP_prime);
	vec3 u = cross_vec3(s, f);
	
	mat4 m = rb_mat4_identity();
	m.entries[M4E(0,0)] = s.coords[0];
	m.entries[M4E(1,0)] = u.coords[0];
	m.entries[M4E(2,0)] = -f.coords[0];
	m.entries[M4E(0,1)] = s.coords[1];
	m.entries[M4E(1,1)] = u.coords[1];
	m.entries[M4E(2,1)] = -f.coords[1];
	m.entries[M4E(0,2)] = s.coords[2];
	m.entries[M4E(1,2)] = u.coords[2];
	m.entries[M4E(2,2)] = -f.coords[2];
	
	return m;
	
}

mat4 rb_mat4_perspective(float fovyInDegrees, float aspectRatio, float znear, float zfar) {
    float ymax, xmax;
    ymax = znear * tanf(fovyInDegrees * M_PI / 360.0);
    //ymin = -ymax;
    //xmin = -ymax * aspectRatio;
    xmax = ymax * aspectRatio;
    return rb_mat4_frustum(-xmax, xmax, -ymax, ymax, znear, zfar);
}

mat4 rb_mat4_frustum(float left, float right, float bottom, float top, float zNear, float zFar) {
	
	float A = (right + left) / (right - left);
	float B = (top + bottom) / (top - bottom);
	float C = -(zFar + zNear) / (zFar - zNear);
	float D = -(2.0f * zFar * zNear) / (zFar - zNear);	
	
	mat4 result = rb_mat4_zero();
	
	result.entries[M4E(0,0)] = ( 2.0f * zNear ) / ( right - left );
	result.entries[M4E(0,2)] = A;
	result.entries[M4E(1,1)] = ( 2.0f * zNear ) / ( top - bottom );
	result.entries[M4E(1,2)] = B;
	result.entries[M4E(2,2)] = C;
	result.entries[M4E(2,3)] = D;
	result.entries[M4E(3,2)] = -1.0f;
	
	return result;
	
}